package per.example.arpproject.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import per.example.arpproject.entity.Script;
import per.example.arpproject.entity.ScriptDetail;
import per.example.arpproject.service.ScriptService;
import per.example.arpproject.utils.FileUtil;
import per.example.arpproject.utils.JsonUtil;
import per.example.arpproject.utils.SnowflakeIdWorker;
import per.example.arpproject.utils.ZipUtil;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
import java.util.*;

/**
 * @author yaozhang Li
 * @ TO DO
 * @createTime 2023/7/10 19:39
 **/
@Service("scriptService")
@Slf4j
public class ScriptServiceImpl implements ScriptService {

    public static final String SCRIPT_PATH = "spritData";

    public static final String SCRIPT_TOTAL_PATH = "total.json";

    public static final String SCRIPT_DATA_PATH = "data.json";

    public static final String PICT_PATH = "pict";

    public static final String rootPath = System.getProperty("user.dir");

    @Override
    public List<Script> getAllScript(){
        String filePath = rootPath + File.separator + SCRIPT_PATH +File.separator+ SCRIPT_TOTAL_PATH;
        File file = new File(filePath);
        if (!file.exists()) {
            return new ArrayList<>();
        }
        try {
            JSONArray jsonArray = JsonUtil.getJsonArrayByFilePath(filePath);
            List<Script> scripts = JSONArray.parseArray(jsonArray.toString(), Script.class);
            return scripts;

        } catch (IOException e) {
            log.error("获取全部脚本失败",e);
            throw new RuntimeException("获取全部脚本失败");
        }

    }

    @Override
    public int addScript(Script entity) {

        long id = SnowflakeIdWorker.getInstance().nextId();
        entity.setId(id);
        entity.setCreateTime(new Date());
        entity.setUpdateTime(new Date());

        String filePath = rootPath + File.separator + SCRIPT_PATH +File.separator+ SCRIPT_TOTAL_PATH;
        File file = new File(filePath);

        try {
            JSONArray jsonArray;
            if (file.exists()) {
                jsonArray = JsonUtil.getJsonArrayByFilePath(filePath);
            } else {
                jsonArray = new JSONArray();
            }

            List<Script> scriptList = JSONArray.parseArray(jsonArray.toString(), Script.class);
            scriptList.add(entity);

            JsonUtil.writeJsonFile(JSONArray.parseArray(JSONArray.toJSONString(scriptList)),filePath);

            //新增文件夹
            String scriptDir = rootPath + File.separator + SCRIPT_PATH +File.separator+ id;
            File dirFile = new File(scriptDir);
            dirFile.mkdirs();

        } catch (Exception e){
            log.error("新增失败",e);
            throw new RuntimeException("新增失败");
        }


        return 1;
    }

    @Override
    public int updateScript(Script entity) {
        String filePath = rootPath + File.separator + SCRIPT_PATH +File.separator+ SCRIPT_TOTAL_PATH;

        if (entity.getId() == null) {
            throw new RuntimeException("id为空");
        }

        List<Script> allScript = getAllScript();

        Optional<Script> optional = allScript.stream().filter(item -> item.getId().equals(entity.getId())).findFirst();
        if (!optional.isPresent()) {
            throw new RuntimeException("不存在该脚本");
        }

        Script script = optional.get();
        entity.setUpdateTime(new Date());

        allScript.remove(script);
        allScript.add(entity);
        try {
            JsonUtil.writeJsonFile(JSONArray.parseArray(JSONArray.toJSONString(allScript)),filePath);

        } catch (IOException e) {
            log.error("修改失败",e);
            throw new RuntimeException("修改失败");
        }

        return 1;
    }

    @Override
    public int deleteScript(Long id,Boolean deleteFile) {
        String filePath = rootPath + File.separator + SCRIPT_PATH +File.separator+ SCRIPT_TOTAL_PATH;

        if (id == null) {
            throw new RuntimeException("id为空");
        }

        List<Script> allScript = getAllScript();

        Optional<Script> optional = allScript.stream().filter(item -> item.getId().equals(id)).findFirst();
        if (!optional.isPresent()) {
            throw new RuntimeException("不存在该脚本");
        }

        Script script = optional.get();
        allScript.remove(script);

        try {
            JsonUtil.writeJsonFile(JSONArray.parseArray(JSONArray.toJSONString(allScript)),filePath);

        } catch (IOException e) {
            log.error("删除失败",e);
            throw new RuntimeException("删除失败");
        }

        if (deleteFile) {
            String dirFile = rootPath + File.separator + SCRIPT_PATH + File.separator + id;
            FileUtil.deleteAllFile(dirFile, true);
        }

        return 1;
    }

    @Override
    public ScriptDetail getDetailById(Long id) {
        if (id == null) {
            throw new RuntimeException("id为空");
        }
        String jsonFile = rootPath + File.separator + SCRIPT_PATH + File.separator + id + File.separator + SCRIPT_DATA_PATH;

        File file = new File(jsonFile);
        if (file.exists()) {
            try {
                return JsonUtil.getJsonObjectByFilePath(jsonFile).toJavaObject(ScriptDetail.class);
            } catch (IOException e) {
                log.error("获取脚本详细失败",e);
                throw new RuntimeException("获取脚本详细失败");
            }
        }

        return new ScriptDetail();
    }

    @Override
    public int updateDetailById(ScriptDetail entity) {
        if (entity.getId() == null) {
            throw new RuntimeException("id为空");
        }
        String jsonFile = rootPath + File.separator + SCRIPT_PATH + File.separator + entity.getId() + File.separator + SCRIPT_DATA_PATH;

        try {
            JsonUtil.writeJsonFile(JSONObject.parseObject(JSONObject.toJSONString(entity)),jsonFile);
            return 1;
        } catch (IOException e) {
            log.error("删除失败",e);
            throw new RuntimeException("删除失败");
        }

    }

    @Override
    public String uploadScriptImg(MultipartFile file, Long id) {
        return null;
    }

    @Override
    public void exportScript(Long id, String withEnv, HttpServletRequest request, HttpServletResponse response) throws IOException {
        //临时文件
        String tmpFilePath = rootPath + File.separator + SCRIPT_PATH + "tmp.zip";
        //脚本文件位置
        String dirPath = rootPath + File.separator + SCRIPT_PATH + File.separator + id;
        String packagePath;
        if ("1".equals(withEnv)) {
            //复制脚本文件，跟环境一起打包
            File src = new File(dirPath);
            packagePath = rootPath + File.separator +"packageTem";
            String packageSpritPath = packagePath + File.separator +"sprit";
            File dest = new File(packageSpritPath);
            FileUtil.deleteAllFile(packageSpritPath,false);
            FileUtil.copyFolder(src,dest);
        } else {
            packagePath = dirPath;
        }

        if (id == null) {
            throw new RuntimeException("id为空");
        }

        try {

            OutputStream outputStream = new FileOutputStream(tmpFilePath);
            ZipUtil.dirToZip(packagePath,outputStream,true);
            String outputFileName = "output.zip";

            // 设置响应
            //根据请求头user-agent
            //attachment打开对话框下载  inline直接打开
            String userAgent = request.getHeader("User-agent");
            String agent = userAgent==null?"":userAgent;
            if(agent.indexOf("Firefox")!=-1) {
                response.addHeader("content-Disposition", "attachment;fileName==?UTF-8?B?"+ Base64.getEncoder().encodeToString(outputFileName.getBytes("utf-8"))+"?=");
            }else if(agent.indexOf("Edg")!=-1) {
                response.addHeader("content-Disposition", "attachment;fileName="+ URLEncoder.encode(outputFileName, "utf-8"));
            }else{
                response.addHeader("content-Disposition", "attachment;fileName="+ URLEncoder.encode(outputFileName, "utf-8"));
            }
            response.setContentType("application/octet-stream");
            response.setCharacterEncoding("utf-8");

            // 文件流操作
            File file = new File(tmpFilePath);
            InputStream inputStream = new FileInputStream(file);
            OutputStream os = response.getOutputStream();
            try {
                byte[] b = new byte[2048];
                int length;
                while ((length = inputStream.read(b)) > 0) {
                    os.write(b, 0, length);
                }
            } finally {
                if(os!=null){
                    os.close();
                }
                if(inputStream!=null){
                    inputStream.close();
                }

                new File(tmpFilePath).delete();
            }
        } catch (Exception e){
            log.error("脚本导出异常",e);
            throw new RuntimeException("脚本导出异常");
        }  
    }

    @Override
    public String uploadPict(Long id, MultipartFile file) throws IOException {
        if (id == null) {
            throw new RuntimeException("id为空");
        }
        long fileName = SnowflakeIdWorker.getInstance().nextId();
        String extsionName = FileUtil.getExtsionName(file);
        File dirFIle = new File(rootPath + File.separator + SCRIPT_PATH + File.separator + id + File.separator + PICT_PATH);
        if (!dirFIle.exists()) {
            dirFIle.mkdirs();
        }

        String path = rootPath + File.separator + SCRIPT_PATH + File.separator + id ;
        String filePath = File.separator + PICT_PATH + File.separator + fileName + "." + extsionName;
        File newFile = new File(path+filePath);
        file.transferTo(newFile);
        return filePath;
    }

    @Override
    public void importScript(MultipartFile file, String name) {
        //压缩文件临时路径
        String temZipFilePath = rootPath + File.separator + SCRIPT_PATH + File.separator + "zipTem";
        //压缩文件路径
        String zipFilePath = temZipFilePath + File.separator + file.getOriginalFilename();

        File temZipFileDir = new File(temZipFilePath);

        if (temZipFileDir.exists()) {
            FileUtil.deleteAllFile(temZipFileDir.getAbsolutePath(),true);

        }
        temZipFileDir.mkdirs();
        File zipFile = new File(zipFilePath);
        try {
            file.transferTo(zipFile);
            ZipUtil.unZipFiles(zipFile,temZipFilePath+File.separator);
        } catch (Exception e){
            log.error("解压失败",e);
            throw new RuntimeException("解压失败");
        } finally {
            zipFile.delete();
        }


        String unZipFileDir = temZipFilePath + File.separator + FileUtil.getName(file);
        File unZipFile = new File(unZipFileDir);
        if(unZipFile.listFiles().length != 1 ){
            throw new RuntimeException("不支持上传多个脚本文件");
        }
        File scriptData = unZipFile.listFiles()[0];
        List<File> fileList = Arrays.asList(scriptData.listFiles());
        Optional<File> optional = fileList.stream().filter(item -> item.getName().equals("data.json")).findFirst();
        if (!optional.isPresent()) {
            throw new RuntimeException("缺少脚本文件信息");
        }

        Script script = new Script();
        script.setName(name);
        addScript(script);
        Long id = script.getId();
        //脚本文件位置
        String dirPath = rootPath + File.separator + SCRIPT_PATH + File.separator + id;
        try {

            FileUtil.copyFolder(scriptData,new File(dirPath));
            String jsonFile = rootPath + File.separator + SCRIPT_PATH + File.separator + id + File.separator + SCRIPT_DATA_PATH;
            JSONObject jsonObject = JsonUtil.getJsonObjectByFilePath(jsonFile);
            jsonObject.put("id",id);
            JsonUtil.writeJsonFile(jsonObject,jsonFile);
        } catch (Exception e){
            new File(dirPath).delete();
            throw new RuntimeException("脚本文件转移失败");
        }
        FileUtil.deleteAllFile(temZipFilePath,true);
    }
}
